package com.dc.schedule.server.service.server.impl;

import com.dc.schedule.server.config.ServerConfig;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.json.JsonObjectDecoder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

@Service
@Slf4j
@RequiredArgsConstructor
public class NettyServerService implements InitializingBean, DisposableBean {
    private final ServerConfig serverConfig;
    private final ChannelInboundHandlerAdapter channelInboundHandlerAdapter;
    private EventLoopGroup bossGroup;
    private EventLoopGroup workGroup;
    
    @Override
    public void destroy() {
        log.info("Shutting down Netty Server...");
        
        try {
            if (bossGroup != null) {
                bossGroup.shutdownGracefully();
            }
        } catch (Exception e) {
            log.error("Netty Boss Group Shutdown Failed ", e);
        }
        try {
            if (workGroup != null) {
                workGroup.shutdownGracefully();
            }
        } catch (Exception e) {
            log.error("Netty Work Group Shutdown Failed ", e);
        }
    }
    
    @Override
    public void afterPropertiesSet() throws InterruptedException {
        bossGroup = new NioEventLoopGroup(1);
        workGroup = new NioEventLoopGroup(serverConfig.getSelectorThreads());
        final ServerBootstrap serverBootstrap = new ServerBootstrap();
        try {
            serverBootstrap.group(bossGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new JsonObjectDecoder())
                                    .addLast(channelInboundHandlerAdapter);
                        }
                    }).childOption(ChannelOption.SO_KEEPALIVE, true)
                    .bind(serverConfig.getSocketBindHost(), serverConfig.getSocketListenPort())
                    .sync();
            log.info("启动Socket服务器 {}:{}", serverConfig.getSocketBindHost(), serverConfig.getSocketListenPort());
        } catch (Exception e) {
            // 这里竟然能够接收到 IOException ？
            log.error("Netty Server Start Failed!!", e);
            this.destroy();
            throw e;
        }
        
    }
    
}
